#include "base/GLObject.h"
#include <FreeImage.h>

GLObject::GLObject(GLuint programHandler, GLShaderConfig shaderConfig) :
	programHandler(programHandler),
	vboHandlers(0),
	vaoHandler(0),
	textureId(0),
	transformMatrix(glm::mat4( 1.0f )),
	colorR(1),
	colorG(1),
	colorB(1),
	useDiffuseTexture(false),
	useDirtTexture(false) {
	this->shaderConfig = new GLShaderConfig(shaderConfig);
}

GLObject::~GLObject() {
	if (vboHandlers != NULL) {
		delete[] vboHandlers;
	}
	delete shaderConfig;
}

void GLObject::init() {
	int attribCount = shaderConfig->getAttributesCount();
	std::map<std::string, VertexAttrib> vertexAttribs = shaderConfig->getAttributesInfo();
	std::map<std::string, BufferConfig> vertexBuffers = shaderConfig->getAttributesBuffer();
	std::map<std::string, VertexAttrib>::iterator vertexAttribIterator = vertexAttribs.begin();
	std::map<std::string, BufferConfig>::iterator vertexBufferIterator = vertexBuffers.begin();

	if (vboHandlers == NULL) {
		vboHandlers = new GLuint[attribCount];
		glGenBuffers(attribCount, vboHandlers);
	}
	for (int i = 0; i < attribCount; i++, vertexAttribIterator++, vertexBufferIterator++) {
		GLuint handle = vboHandlers[i];

		BufferConfig buffer = (*vertexBufferIterator).second;

		glBindBuffer( buffer.target, handle );
		glBufferData( buffer.target, buffer.size, buffer.data, buffer.usage );
	}

	if (vaoHandler == NULL) {
		// Create and set-up the vertex array object
		glGenVertexArrays( 1, &vaoHandler );
	}
	glBindVertexArray( vaoHandler );

	vertexAttribIterator = vertexAttribs.begin();
	vertexBufferIterator = vertexBuffers.begin();

	for (int i = 0; i < attribCount; i++, vertexAttribIterator++, vertexBufferIterator++) {
		GLuint handle = vboHandlers[i];

		VertexAttrib attrib = (*vertexAttribIterator).second;
		BufferConfig buffer = (*vertexBufferIterator).second;

		// Enable the vertex attribute array
		glEnableVertexAttribArray( attrib.index );

		// Map index to the position buffer
		glBindBuffer( buffer.target, handle );
		glVertexAttribPointer( attrib.index, attrib.size, attrib.type, attrib.normalized, attrib.stride, (GLubyte*)attrib.pointer);
	}

	int useDiffuseTextureLocation = glGetUniformLocation(this->programHandler, "UseDiffuseTexture");
	if( useDiffuseTextureLocation >= 0 )
	{
		glUniform1f(useDiffuseTextureLocation, useDiffuseTexture ? 1.0f : 0);
	}
//	else
//	{
//		fprintf(stderr, "Uniform variable UseDiffuseTexture not found!\n");
//	}

	int useDirtTextureLocation = glGetUniformLocation(this->programHandler, "UseDirtTexture");
	if( useDirtTextureLocation >= 0 )
	{
		glUniform1f(useDirtTextureLocation, useDirtTexture ? 1.0f : 0);
	}
//	else
//	{
//		fprintf(stderr, "Uniform variable UseDirtTexture not found!\n");
//	}

	vertexAttribs.clear();
	vertexBuffers.clear();
}

void GLObject::transform(glm::mat4 transformMatrix) {
	this->transformMatrix = transformMatrix;
}

void GLObject::setColor(float r, float g, float b) {
	colorR = r;
	colorG = g;
	colorB = b;
}

void GLObject::changeObjectColor(float r, float g, float b)
{
    glm::vec3 diffuse_reflectivity = glm::vec3( r, g, b );

    GLuint location_diffuse_reflectivity = glGetUniformLocation( this->programHandler, "Kd");
    if( location_diffuse_reflectivity >= 0 )
	{
		glUniform3fv( location_diffuse_reflectivity, 1, &diffuse_reflectivity[0]);
	}
}

//void  GLObject::loadAndInitTexture(const char* filename)
//{
//	//image format
//	FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
//	//pointer to the image, once loaded
//	FIBITMAP *dib(0);
//	//pointer to the image data
//	BYTE* bits(0);
//	//image width and height
//	unsigned int width(0), height(0);
//
//	//check the file signature and deduce its format
//	fif = FreeImage_GetFileType(filename, 0);
//	//if still unknown, try to guess the file format from the file extension
//	if(fif == FIF_UNKNOWN)
//		fif = FreeImage_GetFIFFromFilename(filename);
//	//if still unkown, return failure
//	if(fif == FIF_UNKNOWN)
//		return;
//
//	//check that the plugin has reading capabilities and load the file
//	if(FreeImage_FIFSupportsReading(fif))
//		dib = FreeImage_Load(fif, filename);
//	//if the image failed to load, return failure
//	if(!dib)
//		return;
//
//	//is the file of the correct type
////	FREE_IMAGE_COLOR_TYPE type = FreeImage_GetColorType(dib);
////	if(FIC_RGBALPHA != type)
////	{
////		//convert to type
////		FIBITMAP* ndib = FreeImage_ConvertTo32Bits(dib);
////		dib = ndib;
////	}
//
//	//retrieve the image data
//	bits = FreeImage_GetBits(dib);
//	//get the image width and height
//	width = FreeImage_GetWidth(dib);
//	height = FreeImage_GetHeight(dib);
//	//if this somehow one of these failed (they shouldn't), return failure
//	if((bits == 0) || (width == 0) || (height == 0))
//		return;
//
//    // Copy file to OpenGL
//    glActiveTexture(GL_TEXTURE0);
//    glGenTextures(1, &this->textureId);
//    glBindTexture(GL_TEXTURE_2D, this->textureId);
//
//    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, bits);
////    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bits);
//    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//
//    // Set the Tex1 sampler uniform to refer to texture unit 0
//    int loc = glGetUniformLocation(this->programHandler, "Tex1");
//
//    if( loc >= 0 )
//    {
//        glUniform1i(loc, 0);
//    }
//    else
//    {
//        fprintf(stderr, "Uniform variable Tex1 not found!\n");
//    }
//
//    // Set the UseTexture uniform to use texture
//    int useTextureLocation = glGetUniformLocation(this->programHandler, "UseTexture");
//
//	if( useTextureLocation >= 0 )
//	{
//		useTexture = true;
//		glUniform1f(useTextureLocation, 1.0f);
//	}
//	else
//	{
//		fprintf(stderr, "Uniform variable UseTexture not found!\n");
//	}
//
//    //Free FreeImage's copy of the data
//    FreeImage_Unload(dib);
//}
